﻿using System;
using System.Collections.Generic;
using Language.Utility;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;

namespace Language.Intellisense.QuickInfo
{
    internal class Source : IQuickInfoSource
    {
        #region Private Data

        private ITextBuffer _textBuffer;
        private ITextStructureNavigator _navigator;
        private Stub.Database _database;

        #endregion Private Data

        #region C-Tor

        public Source( ITextBuffer textBuffer, ITextStructureNavigator navigator, Stub.Database database )
        {
            _textBuffer = textBuffer;
            _navigator = navigator;
            _database = database;
        }

        #endregion C-Tor

        #region IQuickInfoSource

        void IQuickInfoSource.AugmentQuickInfoSession( IQuickInfoSession session, IList<object> quickInfoContent, out ITrackingSpan applicableToSpan )
        {
            // Map the trigger point down to our buffer.
            SnapshotPoint? subjectTriggerPoint = session.GetTriggerPoint( _textBuffer.CurrentSnapshot );
            if ( !subjectTriggerPoint.HasValue )
            {
                applicableToSpan = null;
                return;
            }

            // Find the token at the "trigger point" (underneath the mouse cursor)
            Stub.Token token = _database.FindToken( _textBuffer.ExtractFilename(), subjectTriggerPoint.Value.Position, false );

            if ( token == null )
            {
                // There was no token at that location, so do nothing
                applicableToSpan = null;
                return;
            }

            // Find the type for the token we're hovering over
            Stub.DetailedContext typeStub = _database.ResolveContext( token.Declaration );

            // Reconstruct the type declaration from the stub
            string format = DeclarationPrinter.Format( typeStub );

            // Add this string to the tooltip
            quickInfoContent.Add( format );

            // Mark that this quick info content applies to the word at the trigger point (mouse cursor)
            TextExtent extent = _navigator.GetExtentOfWord( subjectTriggerPoint.Value );
            applicableToSpan = _textBuffer.CurrentSnapshot.CreateTrackingSpan( extent.Span.Span, SpanTrackingMode.EdgeInclusive );
        }

        #endregion IQuickInfoSource

        #region IDisposable

        private bool _disposedValue = false; // To detect redundant calls

        protected virtual void Dispose( bool disposing )
        {
            if ( !_disposedValue )
            {
                if ( disposing )
                {
                    // TODO: dispose managed state (managed objects).
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.

                GC.SuppressFinalize( this );
                _disposedValue = true;
            }
        }

        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
        // ~Source() {
        //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        //   Dispose(false);
        // }

        // This code added to correctly implement the disposable pattern.
        void IDisposable.Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose( true );
            // TODO: uncomment the following line if the finalizer is overridden above.
            // GC.SuppressFinalize(this);
        }

        #endregion IDisposable
    }
}
